package novel.manager.service.impl.spider.novel;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import novel.manager.pojo.spider.NovelSiteEnum;
import novel.manager.pojo.web.Novel;
import novel.manager.service.iface.spider.novel.INovelSpider;
import novel.manager.service.impl.spider.AbstractSpider;
import novel.manager.service.utils.NovelSpiderUtil;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**翻页抓取小说列表并解析tr元素的方法 */
public abstract class AbstractNovelSpider extends AbstractSpider implements INovelSpider {
	/**含有下一页链接的元素*/
	protected Element nextPageElement;
	/** 下一页的url */
	protected String nextPage;
	/** 默认的抓取方法，最多会尝试 {@link INovelSpider#MAX_TRY_TIMES} 次下载*/
	protected Elements getsTr(String url) throws Exception {
		return getsTr(url, INovelSpider.MAX_TRY_TIMES);
	}
	/**以指定次数的形式去解析对应网页，获取小说列表elements*/
	//url:小说列表页面
	protected Elements getsTr(String url, Integer maxTryTimes) throws Exception {
		maxTryTimes = maxTryTimes == null ? INovelSpider.MAX_TRY_TIMES : maxTryTimes;
		Elements elements = null;
		for (int i = 0; i < maxTryTimes ; i++) {
			try {
				//抓取小说列表页面
				String result = super.crawl(url);
				//获取站点规则
				Map<String, String> context = NovelSpiderUtil.getSpiderRuleMapByNovelSiteEnum(NovelSiteEnum.getEnumByUrl(url));
				//获取小说列表抓取规则
				String novelSelector = context.get("novel-selector");
				//判断该站点是否能够抓取
				if (novelSelector == null) throw new RuntimeException(NovelSiteEnum.getEnumByUrl(url).getUrl() + ",url=" + url + "目前不支持抓取小说列表");
				//jsoup解析String2Document
				Document doc = Jsoup.parse(result);
				//设置小说列表页面为jsoup根路径
				doc.setBaseUri(url);
				//抓取小说列表
				elements = doc.select(novelSelector);
				//小说列表翻页
				String nextPageSelector = context.get("novel-next-page-selector");
				if (nextPageSelector != null) {
					Elements nextPageElements = doc.select(nextPageSelector);
					//获取含有下一页链接的元素
					//在这里打个断点来查看翻页是否正常
					nextPageElement = nextPageElements == null ? null : nextPageElements.first();					
					if (nextPageElement != null) {
						//获取含有下一页链接的元素中的href即下一页的url
						nextPage = nextPageElement.absUrl("href");
					} else {
						nextPage = "";
					}
					System.out.println("nextPage"+nextPage);
				}
				return elements;
			} catch (Exception e) {
				e.printStackTrace();
				System.err.println(url+",getsTr第"+i+"次尝试下载失败");
			}
		}
		//抛出异常后上层没有处理，所以程序停止
		//throw new RuntimeException(url + ",尝试了" + maxTryTimes + "次依然下载失败了！");
		//不抛出异常，直接打印异常算了
		System.err.println(url+",getsTr 3次尝试下载失败");
		return null;
	}
	
	@Override
	public boolean hasNext() {
		return !nextPage.isEmpty();
	}

	@Override
	public String next() {
		//返回含有下一页链接的元素中的href即下一页的url
		return nextPage;
	}
	/**把第一页赋值给下一页，返回一个迭代器，从第一页开始迭代*/
	@Override
	public Iterator<List<Novel>> iterator(String firstPage, Integer maxTryTimes) {
		nextPage = firstPage;
		//返回专门用于对小说网站数据列表抓取的迭代器
		return new NovelIterator(maxTryTimes);
	}
	/**
	 * 定义专门用于对小说网站数据列表抓取的迭代器，覆盖接口方法
	 */
	private class NovelIterator implements Iterator<List<Novel>> {
		private Integer maxTryTimes;
		public NovelIterator(Integer maxTryTimes) {
			this.maxTryTimes = maxTryTimes;
		}
		@Override
		public boolean hasNext() {
			//内部类调用外部类的同名方法
			return AbstractNovelSpider.this.hasNext();
		}
		@Override
		public List<Novel> next() {
			//抽象类实现接口，抽象类不要求覆盖接口方法，但抽象类+抽象类的子非抽象类合起来要覆盖接口的全部方法
			//抽象类调用抽象类的子非抽象类的方法
			//小说列表的爬取
			List<Novel> novels = getNovels(nextPage, maxTryTimes);
			return novels;
		}
		@Override
		public void remove() {
			// TODO Auto-generated method stub
			
		}
	}
}
